/**
 * TODO need corresponding HTML code structure to cooperate
 */

import { assert } from '@/lib/utils';

export interface FormsetManagerData {
    prefix: string;
    totalFormsId: string;
}

export interface FormsetConfig {
    [key: string]: FormsetManagerData;
}

export class FormsetManager {
    private static readonly FORM_COUNT_REGEX = /form-(\d+|__prefix__)/;
    private keyword: string;
  
    constructor(keyword: string) {
        this.keyword = keyword;
    }

    public updateFormIndices(container: HTMLElement): void {
        const forms = Array.from(container.children).filter(
            element => element.hasAttribute('data-form')
        );

        const totalFormsInputID = `id_${this.keyword}-TOTAL_FORMS`;
        const totalFormsInput = document.getElementById(totalFormsInputID) as HTMLInputElement;
        assert(totalFormsInput, `Total forms input with id '${totalFormsInputID}' not found.`);
        
        forms.forEach((form, newIndex) => {
            const currentIndex = this.extractFormIndex(form);
            if (currentIndex !== null) {
                this.updateFormIndex(form, currentIndex, newIndex);
            }
        });

        totalFormsInput.value = forms.length.toString();
    }

    private extractFormIndex(element: Element): string | null {
        const match = element.id.match(FormsetManager.FORM_COUNT_REGEX);
        return match ? match[1] : null;
    }

    private updateFormIndex(form: Element, oldIndex: string, newIndex: number): void {
        form.id = form.id.replace(`form-${oldIndex}`, `form-${newIndex}`);

        const elements = form.querySelectorAll('input, select, label, textarea');
        elements.forEach(element => {
            ['name', 'id', 'for'].forEach(attr => {
                if (element.hasAttribute(attr)) {
                    const oldValue = element.getAttribute(attr)!;
                    const newValue = oldValue.replace(
                        `${this.keyword}-${oldIndex}`,
                        `${this.keyword}-${newIndex}`
                    );
                    element.setAttribute(attr, newValue);
                }
            });
        });
    }


    public deleteForm(form: HTMLElement): void {
        // Instead of removing the form, hide it and mark as deleted
        form.style.display = 'none';
        form.setAttribute('data-deleted', 'true');

        // Find or create the DELETE input field
        const formIndex = this.extractFormIndex(form);
        assert(formIndex, "formIndex is null!")
        
        const deleteInputName = `${this.keyword}-${formIndex}-DELETE`;
        let deleteInput = form.querySelector(`input[name="${deleteInputName}"]`) as HTMLInputElement;
        
        if (!deleteInput) {
            // Create DELETE input if it doesn't exist
            deleteInput = document.createElement('input');
            deleteInput.type = 'hidden';
            deleteInput.name = deleteInputName;
            form.appendChild(deleteInput);
        }
        deleteInput.value = 'on';
    }
}


export function setupFormsetHandlers(formsetKeywords: string[]): void {
    const formsetManagers = new Map<string, FormsetManager>();

    formsetKeywords.forEach(keyword => {
        const manager = new FormsetManager(keyword);
        formsetManagers.set(`${keyword}-formset`, manager);
    })

    // Global click handler using event delegation
    document.addEventListener('click', (event) => {
        const target = event.target as HTMLElement;
        if (target.matches('[data-delete-form]')) {
            event.preventDefault();
            
            const formElem = target.closest('[data-form]') as HTMLElement;
            assert(formElem, "formElem not found!")
            
            // Find the containing formset
            const formsetContainer = formElem.parentElement.closest('[id]');
            assert(formsetContainer, "formsetContainer not found!")
            
            const manager = formsetManagers.get(formsetContainer.id);
            if (manager) {
                manager.deleteForm(formElem);
            }
        }
    });
    
    document.addEventListener('htmx:afterSwap', (event: Event) => {
        const htmxEvent = event as CustomEvent;
        const target = htmxEvent.detail.target as HTMLElement;
    
        const manager = formsetManagers.get(target.id);
        if (manager) {
            manager.updateFormIndices(target);
        }
    });
}

